#pragma once

#include <string>
#include <cstring>
#include <iostream>
#include <jsoncpp/json/json.h>

const std::string SEP = " ";
const size_t SEP_LEN = SEP.size();
const std::string LINE_SKIP = "\r\n";
const size_t LINE_SKIP_LEN = LINE_SKIP.size();

enum
{
    DIV_ERRO = 1,
    MOD_ERRO,
    OPERA_ERRO
};

//"x op y" -> lenth\\r\\n"x op y"\\r\\n
//添加报头
const std::string enLenth(const std::string& masg)
{
    std::string response = std::to_string(masg.size());
    response += (LINE_SKIP + masg + LINE_SKIP);
    return response;
}

/* lenth\r\n"x op y"\r\n -> "x op y"
去除报头*/
bool deLenth(const std::string& package, std::string* out)
{
    auto pos = package.find(LINE_SKIP);
    if (pos == std::string::npos)
        return false;

    int masg_lenth = std::stoi(package.substr(0, pos));

    *out = package.substr(pos + LINE_SKIP_LEN, masg_lenth);

    return true;
}

// 接收请求字节流
bool recvPackge(int sockfd, std::string& inbuffer, std::string* request)
{
    char buffer[1024]; 
    while (true)
    {
        ssize_t n = recv(sockfd, buffer, sizeof(buffer)-1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            inbuffer += buffer;

#ifdef DEBUG
            std::cout << inbuffer << std::endl;
#endif
            // lenth\r\n"x op y"\r\n -> "x op y"
            auto len = inbuffer.find(LINE_SKIP);
            if (len == std::string::npos)
            {
                continue;
            }
            std::string str_text_len = inbuffer.substr(0, len);
            int text_len = std::stoi(str_text_len);
            int total_len = text_len + 2 * LINE_SKIP_LEN + str_text_len.size();
#ifdef DEBUG
            std::cout << "处理前的inbuffer: \n"
                      << inbuffer << std::endl;
#endif
            if (inbuffer.size() < total_len)
            {
                std::cout << "你输入的消息，没有严格遵守我们的协议，正在等待后续的内容, continue" << std::endl;
                continue;
            }

            *request = inbuffer.substr(0, total_len);
            inbuffer.erase(0, total_len);
#ifdef DEBUG
            std::cout << "处理后的inbuffer \n"
                      << inbuffer << std::endl;
#endif
            break;
        }
        else 
        {
#ifdef DEBUG
            std::cout << "收包错误" << std::endl;
#endif
            return false;
        }
    }
    return true;
}

class Request
{
public:
    Request()
        : _x(0), _y(0), _op(0)
    {}
    Request(int x, int y, char op)
        : _x(x), _y(y), _op(op)
    {}

    //"x op y"
    // 取内容
    bool serialize(std::string *out)
    {
#ifdef MYSEL
        //结构化
        out->clear();
        *out = std::to_string(_x) + SEP + _op + SEP + std::to_string(_y);

#else 

        Json::Value root;

        root["x"] = _x;
        root["y"] = _y;
        root["operator"] = _op;

        Json::FastWriter writer;
        // Json::StyledWriter writer;
        *out = writer.write(root);

#endif //MYSEL
        return true;
    }

    //反序列化：将内容切割
    bool deserialize(const std::string &in)
    {
        Json::Value root;
        Json::Reader read;

        read.parse(in, root);
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _op = root["operator"].asInt();

#ifdef MYSEL
        //"x op y"
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);
        if ( (left==std::string::npos || right==std::string::npos) 
            || (left == right) 
            || (right-left-SEP_LEN != 1) )
        {
#ifdef DEBUG
            std::cout << in << " " << in.size() << " " << left << " " << right << " " << std::endl;
#endif //DEBUG
            return false;
        }
        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right);

        _x = std::stoi(x_string);
        _y = std::stoi(y_string);
        _op = in[left + SEP_LEN];
#endif //MYSEL
        return true;
    }

public:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response()
        : _exitcode(0), _result(0)
    {}

    // "exitcode result"
    bool serialize(std::string *out)
    {
#ifdef MYSEL
            out->clear();
        *out = std::to_string(_exitcode) + SEP + std::to_string(_result);

#else 

        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif        
        return true;
    }

    bool deserialize(const std::string &in)
    {

#ifdef MYSEL
        auto mid = in.find(SEP);
        if (mid == std::string::npos)
            return false;

        _exitcode = std::stoi(in.substr(0, mid));
        _result = std::stoi(in.substr(mid));

#else 

        Json::Value root;
        Json::Reader read;

        read.parse(in, root);

        _exitcode = root["exitcode"].asInt();
        _result = root["result"].asInt();

#endif
        return true;
    }

public:
    int _exitcode; 
    int _result;
};